11026. Задача группирования
Имеется n чисел. Выберем из них группу из k элементов. Две группы считаются разными, если существует хотя бы
один элемент, который принадлежит одной группе и не принадлежит другой.
Группирующей системой будем называть множество всех возможных групп. Например,
из четырех элементов a, b, c,
d можно составить шесть групп по два
элемента. Группирующей системой для множества {a, b, c, d}
и k = 2 будет множество {ab, ac,
ad, bc, bd, cd}.
Похожестью группирующей системы
называется число, равное сумме произведений всех элементов групп, взятой по
модулю m. Похожесть для
представленного выше примера для k =
1 равна F1 = (a + b + c
+ d) mod m. Для k = 2 похожесть
равна F2 = (ab + ac + ad
+ bc + bd + cd) mod m.
Для заданного множества чисел и среди
всех всевозможных k = 1, …, n найти похожесть Fk с максимальным значением.
Вход. Первая
строка каждого теста содержит числа n
(2 £ n £ 1000) и m (1 £ m £ 231). Следующая строка содержит n положительных целых чисел. Все числа не более 1000. Последний
тест содержит n = m = 0 и не обрабатывается.
Выход. Для каждого теста вывести
значение максимальной похожести среди всех возможных групп.
4 10
1 2 3 4
4 100
1 2 3 4
4 6
1 2 3 4
0 0
5
50
5
динамическое программирование
Пусть
а1, a2, …, an
– заданные n чисел. Обозначим через Fik (i ³ k) сумму всех возможных
произведений по k чисел, взятых среди
первых i чисел a1, …, ai.
Построим следующую таблицу Fik:
i \ k |
1 |
2 |
3 |
1 |
a1 |
|
|
2 |
a1 + a2 |
a1a2 |
|
3 |
a1 + a2 + a3 |
a1a2 + a1a3 + a2a3 |
a1a2a3 |
Имеют
место следующие рекуррентные соотношения:
Fi1 = F(i-1)1 + ai,
Fii = F(i-1) (i-1) * ai,
1 £ i £ n
Fik = F(i-1)k + F(i-1) (k-1) * ai, 1 £ i £ n, 1 < k < i
Значения каждой следующей строки
пересчитываются через значения предыдущей строки, поэтому в памяти достаточно
хранить один линейный массив d размера 1000. При этом пересчет значений i - ой строки следует начинать с конца:
сначала вычислить Fii,
потом Fi(i-1) и так далее до Fi1. Все вычисления
следует проводить по модулю m.
Пример
Рассмотрим первый тест. Построим
две таблицы: вычисления во второй будут производиться по модулю m = 10, а в первой – нет.
i \ k |
1 |
2 |
3 |
4 |
|
i \ k |
1 |
2 |
3 |
4 |
1 |
1 |
|
|
|
|
1 |
1 |
|
|
|
2 |
3 |
2 |
|
|
|
2 |
3 |
2 |
|
|
3 |
6 |
11 |
6 |
|
|
3 |
6 |
1 |
6 |
|
4 |
10 |
35 |
50 |
24 |
|
4 |
0 |
5 |
0 |
4 |
Ответом является максимальное
число в четвертой строке второй таблицы.
Объявим линейный массив d, в
котором будут пересчитываться значения Fik.
long long d[1000];
Вводим количество чисел n и значение m. Для каждого входного теста изначально обнуляем массив d. Первое
число a1 заносим в d[0].
while(scanf("%lld
%lld",&n,&m), n + m > 0)
{
memset(d,0,sizeof(d));
scanf("%lld",&d[0]);
Вводим значение num = ai+1 (1 £ i < n) и пересчитываем
значения Fik, k = i,
i – 1, …, 1 по выше приведенным
рекуррентным формулам. Все вычисления проводим по модулю m.
for(i = 1; i
< n; i++)
{
scanf("%lld",&num);
d[i] = (d[i-1] * num) % m;
for(j = i -
1; j > 0; j--)
d[j] = (d[j-1] * num + d[j]) % m;
d[0] = (d[0] + num) % m;
}
Находим максимальное значение
среди элементов массива d и заносим его в переменную res. Выводим результат.
res = d[0];
for(i = 1; i
< n; i++)
if (d[i]
> res) res = d[i];
printf("%lld\n",res);
}